package com.dmall.trade;

import com.dmall.promotion.core.PromotionEngine;
import com.dmall.trade.factory.BeanFactory;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

/**
 * @author xiao1.wang
 * @date 2021/6/4 21:28
 */
public class Application {

    private static boolean init = false;

    public synchronized static final void init() throws Exception {
        if (init) {
            return;
        }
        Reflections f = new Reflections("com.dmall");
        Set<Class<?>> classes1 = f.getTypesAnnotatedWith(Component.class);
        Set<Class<?>> classes2 = f.getTypesAnnotatedWith(Controller.class);
        Set<Class<?>> classes3 = f.getTypesAnnotatedWith(Service.class);
        Set<Class<?>> classes4 = f.getTypesAnnotatedWith(Repository.class);
        Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.addAll(classes1);
        classes.addAll(classes2);
        classes.addAll(classes3);
        classes.addAll(classes4);
        for (Class<?> clazz : classes) {
            initialize(clazz);
        }
        init = true;
        System.out.println("初始化完成");
    }

    private static final void initialize(Class clazz) throws InstantiationException, IllegalAccessException {
        // 初始化分两步：1.初始化bean；2.初始化bean的属性
        initializeBean(clazz);
    }

    private static final void initializeBean(Class clazz) throws IllegalAccessException, InstantiationException {
        Object bean = BeanFactory.getBean(clazz);
        if (bean != null) {
            return;
        }
        bean = clazz.newInstance();
        BeanFactory.addBean(clazz, bean);
        initializeFields(clazz, bean);
    }

    private static final void initializeFields(Class clazz, Object bean) throws IllegalAccessException, InstantiationException {
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            boolean present1 = declaredField.isAnnotationPresent(Resource.class);
            boolean present2 = declaredField.isAnnotationPresent(Autowired.class);
            if (present1 || present2) {
                // 如果有注解
                Class<?> fieldType = declaredField.getType();
                Object fieldBean = BeanFactory.getBean(fieldType);
                if (fieldBean != null) {
                    declaredField.setAccessible(true);
                    declaredField.set(bean, fieldBean);
                } else {
                    initializeBean(fieldType);
                    initializeField(bean, declaredField, BeanFactory.getBean(fieldType));
                }
            }
        }
    }

    private static final void initializeField(Object bean, Field field, Object fieldBean) throws IllegalAccessException {
        if (bean == null || field == null || fieldBean == null) {
            return;
        }
        field.setAccessible(true);
        Object fieldValue = field.get(bean);
        if (fieldValue != null) {
            return;
        }
        field.set(bean, fieldBean);
    }

    public static void main(String[] args) throws Exception {
        init();
        calculate(100);
    }

    public static void calculate(int num) {
        PromotionEngine promotionEngine = BeanFactory.getBean(PromotionEngine.class);
        System.out.println(promotionEngine.calculate(num));
    }
}
